﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq.Mapping;
using System.Linq.Expressions;
using CoolCode.Linq.Expressions;

namespace CoolCode.Entities
{
    public class ProductCriterion
    {
        //public SpecType SpecType { get; set; }

        [Column(IsPrimaryKey = true)]
        public string ProductSpec { get; set; }

        public decimal MinODFar { get; set; }

        public decimal MaxODFar { get; set; }

        public decimal MinODClose { get; set; }

        public decimal MaxODClose { get; set; }

        public decimal MinConeHeight { get; set; }

        public decimal MaxConeHeight { get; set; }

        public decimal MinSacculusLength { get; set; }

        public decimal MaxSacculusLength { get; set; }

        public decimal MinSacculusStretch { get; set; }

        public decimal MaxSacculusStretch { get; set; }

        public decimal MinODStressTest2 { get; set; }

        public decimal MaxODStressTest2 { get; set; }

        public decimal MinStressTestLength { get; set; }

        public decimal MaxStressTestLength { get; set; }
    }

    public enum ProductCriterionType
    {
        CountODFar,

        CountODClose,

        CountConeHeight,

        CountSacculusLength,

        CountSacculusStretch,

        CountODStressTest2,

        CountStressTestLength,
    }


    /// <summary>
    /// 产品标准查询提供者
    /// </summary>
    public class ProductCriterionProvider
    {
        private IEnumerable<IProductCriterion> _criterions;

        public ProductCriterionProvider(List<ProductCriterion> criterions)
        {
            _criterions = RegisterProductCriterion(criterions);
        }

        public Expression<Func<Inspection, bool>> CreatePassExpression<T>() where T : IProductCriterion
        {
            var criterions = GetProductCriterion<T>();
            Expression<Func<Inspection, bool>> cond = c => false;
            if (criterions.Count() == 0)
                throw new Exception("没有找到产品标准的相关数据！");
            foreach (var criterion in criterions)
            {
                cond = cond.Or(criterion.CreatePassExpression());
            }
            return cond;
        }

        public IEnumerable<IProductCriterion> GetProductCriterion<T>() where T : IProductCriterion
        {
            return _criterions.Where(c => c is T);
        }

        protected virtual IEnumerable<IProductCriterion> RegisterProductCriterion(List<ProductCriterion> list)
        {
            foreach (var criterion in list)
            {
                yield return new ODFarCriterion
                {
                    MinValue = criterion.MinODFar,
                    MaxValue = criterion.MaxODFar,
                    ProductSpec = criterion.ProductSpec
                };
                yield return new ODCloseCriterion
                {
                    MinValue = criterion.MinODClose,
                    MaxValue = criterion.MaxODClose,
                    ProductSpec = criterion.ProductSpec
                };
                yield return new ConeHeightCriterion
                {
                    MinValue = criterion.MinConeHeight,
                    MaxValue = criterion.MaxConeHeight,
                    ProductSpec = criterion.ProductSpec
                };
                yield return new SacculusLengthCriterion
                {
                    MinValue = criterion.MinSacculusLength,
                    MaxValue = criterion.MaxSacculusLength,
                    ProductSpec = criterion.ProductSpec
                };
                yield return new SacculusStretchCriterion
                {
                    MinValue = criterion.MinSacculusStretch,
                    MaxValue = criterion.MaxSacculusStretch,
                    ProductSpec = criterion.ProductSpec
                };
                yield return new ODStressTest2Criterion
                {
                    MinValue = criterion.MinODStressTest2,
                    MaxValue = criterion.MaxODStressTest2,
                    ProductSpec = criterion.ProductSpec
                };
                yield return new StressTestLengthCriterion
                {
                    MinValue = criterion.MinStressTestLength,
                    MaxValue = criterion.MaxStressTestLength,
                    ProductSpec = criterion.ProductSpec
                };
            }
        }
    }

    public interface IProductCriterion
    {
        Expression<Func<Inspection, bool>> CreatePassExpression();
    }

    /// <summary>
    /// 产品标准基类
    /// </summary>
    public abstract class BaseCriterion : IProductCriterion
    {
        public string ProductSpec { get; set; }
        public decimal MinValue { get; set; }
        public decimal MaxValue { get; set; }

        public abstract Expression<Func<Inspection, bool>> CreatePassExpression();
    }

    public class ODFarCriterion : BaseCriterion
    {
        public override Expression<Func<Inspection, bool>> CreatePassExpression()
        {
            Expression<Func<Inspection, bool>> cond = c =>
               (c.ProductSpec == ProductSpec) &&
               (c.ODFar >= MinValue && c.ODFar <= MaxValue);
            return cond;
        }
    }

    public class ODCloseCriterion : BaseCriterion
    {
        public override Expression<Func<Inspection, bool>> CreatePassExpression()
        {
            Expression<Func<Inspection, bool>> cond = c =>
               (c.ProductSpec == ProductSpec) &&
               (c.ODClose >= MinValue && c.ODClose <= MaxValue);
            return cond;
        }
    }

    public class ConeHeightCriterion : BaseCriterion
    {
        public override Expression<Func<Inspection, bool>> CreatePassExpression()
        {
            Expression<Func<Inspection, bool>> cond = c =>
               (c.ProductSpec == ProductSpec) &&
               (c.ConeHeight >= MinValue && c.ConeHeight <= MaxValue);
            return cond;
        }
    }

    public class SacculusLengthCriterion : BaseCriterion
    {
        public override Expression<Func<Inspection, bool>> CreatePassExpression()
        {
            Expression<Func<Inspection, bool>> cond = c =>
               (c.ProductSpec == ProductSpec) &&
               (c.SacculusLength >= MinValue && c.SacculusLength <= MaxValue);
            return cond;
        }
    }

    public class SacculusStretchCriterion : BaseCriterion
    {
        public override Expression<Func<Inspection, bool>> CreatePassExpression()
        {
            Expression<Func<Inspection, bool>> cond = c =>
               (c.ProductSpec == ProductSpec) &&
               (c.SacculusStretch >= MinValue && c.SacculusStretch <= MaxValue);
            return cond;
        }
    }

    public class ODStressTest2Criterion : BaseCriterion
    {
        public override Expression<Func<Inspection, bool>> CreatePassExpression()
        {
            Expression<Func<Inspection, bool>> cond = c =>
               (c.ProductSpec == ProductSpec) &&
               (c.ODStressTest2 >= MinValue && c.ODStressTest2 <= MaxValue);
            return cond;
        }
    }

    public class StressTestLengthCriterion : BaseCriterion
    {
        public override Expression<Func<Inspection, bool>> CreatePassExpression()
        {
            Expression<Func<Inspection, bool>> cond = c =>
               (c.ProductSpec == ProductSpec) &&
               (c.StressTestLength >= MinValue && c.StressTestLength <= MaxValue);
            return cond;
        }
    }



    ///// <summary>
    ///// 合格产品信息
    ///// </summary>
    //public class PassProductInfo
    //{
    //    public int CountODFar { get; set; }

    //    public int CountODClose { get; set; }

    //    public int CountConeHeight { get; set; }

    //    public int CountSacculusLength { get; set; }

    //    public int CountSacculusStretch { get; set; }

    //    public int CountODStressTest2 { get; set; }

    //    public int CountStressTestLength { get; set; }
    //}
}
